home *** CD-ROM | disk | FTP | other *** search
/ Aminet 35 / Aminet 35 (2000)(Schatztruhe)[!][Feb 2000].iso / Aminet / game / shoot / ADescentSrc.lha / descent / main / dumpmine.c < prev    next >
C/C++ Source or Header  |  1998-08-08  |  32KB  |  1,069 lines

  1. /*
  2.  * $Source: /usr/CVS/descent/main/dumpmine.c,v $
  3.  * $Revision: 1.2 $
  4.  * $Author: nobody $
  5.  * $Date: 1998/08/08 15:43:18 $
  6.  * 
  7.  * Functions to dump text description of mine.
  8.  * An editor-only function, called at mine load time.
  9.  * To be read by a human to verify the correctness and completeness of a mine.
  10.  * 
  11.  * $Log: dumpmine.c,v $
  12.  * Revision 1.2  1998/08/08 15:43:18  nobody
  13.  * Activated the Editior
  14.  *
  15.  * Revision 1.1.1.1  1998/03/03 15:12:14  nobody
  16.  * reimport after crash from backup
  17.  *
  18.  * Revision 1.1.1.1  1998/02/13  20:20:46  hfrieden
  19.  * Initial Import
  20.  *
  21.  * Revision 2.1  1995/04/06  12:21:50  mike
  22.  * Add texture map information to txm files.
  23.  * 
  24.  * Revision 2.0  1995/02/27  11:26:41  john
  25.  * New version 2.0, which has no anonymous unions, builds with
  26.  * Watcom 10.0, and doesn't require parsing BITMAPS.TBL.
  27.  * 
  28.  * Revision 1.24  1995/01/23  15:34:43  mike
  29.  * New diagnostic code, levels.all stuff.
  30.  * 
  31.  * Revision 1.23  1994/12/20  17:56:36  yuan
  32.  * Multiplayer object capability.
  33.  * 
  34.  * Revision 1.22  1994/11/27  23:12:19  matt
  35.  * Made changes for new mprintf calling convention
  36.  * 
  37.  * Revision 1.21  1994/11/23  12:19:04  mike
  38.  * move out level names, stick in gamesave.
  39.  * 
  40.  * Revision 1.20  1994/11/21  16:54:36  mike
  41.  * oops.
  42.  * 
  43.  * 
  44.  * Revision 1.19  1994/11/20  22:12:55  mike
  45.  * Lotsa new stuff in this fine debug file.
  46.  * 
  47.  * Revision 1.18  1994/11/17  14:58:09  mike
  48.  * moved segment validation functions from editor to main.
  49.  * 
  50.  * Revision 1.17  1994/11/15  21:43:02  mike
  51.  * texture usage system.
  52.  * 
  53.  * Revision 1.16  1994/11/15  12:45:59  mike
  54.  * debug code for dumping texture info.
  55.  * 
  56.  * Revision 1.15  1994/11/14  20:47:50  john
  57.  * Attempted to strip out all the code in the game 
  58.  * directory that uses any ui code.
  59.  * 
  60.  * Revision 1.14  1994/10/14  17:33:38  mike
  61.  * Fix error reporting for number of multiplayer objects in mine.
  62.  * 
  63.  * Revision 1.13  1994/10/14  13:37:46  mike
  64.  * Forgot parameter in fprintf, was getting bogus number of excess keys.
  65.  * 
  66.  * Revision 1.12  1994/10/12  08:05:33  mike
  67.  * Detect keys contained in objects for error checking (txm file).
  68.  * 
  69.  * Revision 1.11  1994/10/10  17:02:08  mike
  70.  * fix fix.
  71.  * 
  72.  * Revision 1.10  1994/10/10  17:00:37  mike
  73.  * Add checking for proper number of players.
  74.  * 
  75.  * Revision 1.9  1994/10/03  23:37:19  mike
  76.  * Adapt to clear and rational understanding of matcens as related to fuelcens as related to something that might work.
  77.  * 
  78.  * Revision 1.8  1994/09/30  17:15:29  mike
  79.  * Fix error message, was telling bogus filename.
  80.  * 
  81.  * Revision 1.7  1994/09/30  11:50:55  mike
  82.  * More diagnostics.
  83.  * 
  84.  * Revision 1.6  1994/09/28  17:31:19  mike
  85.  * More error checking.
  86.  * 
  87.  * Revision 1.5  1994/09/28  11:14:05  mike
  88.  * Better checking on bogus walls.
  89.  * 
  90.  * Revision 1.4  1994/09/28  09:23:50  mike
  91.  * Change some Error messages to Warnings.
  92.  * 
  93.  * Revision 1.3  1994/09/27  17:08:31  mike
  94.  * More mine validation stuff.
  95.  * 
  96.  * Revision 1.2  1994/09/27  15:43:22  mike
  97.  * The amazing code to tell you everything and more about our mines!
  98.  * 
  99.  * Revision 1.1  1994/09/27  10:51:15  mike
  100.  * Initial revision
  101.  * 
  102.  * 
  103.  */
  104.  
  105.  
  106. #pragma off (unreferenced)
  107. static char rcsid[] = "$Id: dumpmine.c,v 1.2 1998/08/08 15:43:18 nobody Exp $";
  108. #pragma on (unreferenced)
  109.  
  110. #include <stdio.h>
  111. //#include <stdlib.h>
  112. //#include <math.h>
  113. #include <string.h>
  114. #include <stdarg.h>
  115.  
  116. #include "mono.h"
  117. #include "key.h"
  118. #include "gr.h"
  119. #include "palette.h"
  120.  
  121. #include "inferno.h"
  122. #ifdef EDITOR
  123. #include "editor/editor.h"
  124. #endif
  125. #include "error.h"
  126. #include "object.h"
  127. //#include "game.h"
  128. //#include "screens.h"
  129. #include "wall.h"
  130. #include "gamemine.h"
  131. #include "robot.h"
  132. #include "player.h"
  133. #include "newmenu.h"
  134. #include "textures.h"
  135.  
  136. //#include "cflib.h"
  137. //#include "nocfile.h"
  138. #include "bm.h"
  139. #include "menu.h"
  140. #include "switch.h"
  141. #include "fuelcen.h"
  142. #include "powerup.h"
  143. #include "hostage.h"
  144. //#include "weapon.h"
  145. //#include "newdemo.h"
  146. #include "gameseq.h"
  147. //#include "automap.h"
  148. #include "polyobj.h"
  149. //#include "text.h"
  150. //#include "gamefont.h"
  151. #include "gamesave.h"
  152.  
  153.  
  154. #ifdef EDITOR
  155.  
  156. extern ubyte bogus_data[64*64];
  157. extern grs_bitmap bogus_bitmap;
  158.  
  159. //  --------------------------------------------------------------------------------
  160. char    *object_types(int objnum)
  161. {
  162.     int type = Objects[objnum].type;
  163.  
  164.     Assert((type >= 0) && (type < MAX_OBJECT_TYPES));
  165.     return  &Object_type_names[type];
  166. }
  167.  
  168. //  --------------------------------------------------------------------------------
  169. char    *object_ids(int objnum)
  170. {
  171.     int type = Objects[objnum].type;
  172.     int id = Objects[objnum].id;
  173.  
  174.     switch (type) {
  175.         case OBJ_ROBOT:
  176.             return &Robot_names[id];
  177.             break;
  178.         case OBJ_POWERUP:
  179.             return &Powerup_names[id];
  180.             break;
  181.     }
  182.  
  183.     return  NULL;
  184. }
  185.  
  186. void err_printf(FILE *my_file, char * format, ... )
  187. {
  188.     va_list args;
  189.     char        message[256];
  190.  
  191.     va_start(args, format );
  192.     vsprintf(message,format,args);
  193.     va_end(args);
  194.  
  195.     mprintf((1, "%s", message));
  196.     fprintf(my_file, "%s", message);
  197.     Errors_in_mine++;
  198. }
  199.  
  200. void warning_printf(FILE *my_file, char * format, ... )
  201. {
  202.     va_list args;
  203.     char        message[256];
  204.  
  205.     va_start(args, format );
  206.     vsprintf(message,format,args);
  207.     va_end(args);
  208.  
  209.     mprintf((0, "%s", message));
  210.     fprintf(my_file, "%s", message);
  211. }
  212.  
  213. //  -----------------------------------------------------------------------------------------------------------
  214. void write_exit_text(FILE *my_file)
  215. {
  216.     int i, j, count;
  217.  
  218.     fprintf(my_file, "-----------------------------------------------------------------------------\n");
  219.     fprintf(my_file, "Exit stuff\n");
  220.  
  221.     //  ---------- Find exit triggers ----------
  222.     count=0;
  223.     for (i=0; i<Num_triggers; i++)
  224.         if (Triggers[i].flags & TRIGGER_EXIT) {
  225.             int count2;
  226.  
  227.             fprintf(my_file, "Trigger %2i, is an exit trigger with %i links.\n", i, Triggers[i].num_links);
  228.             count++;
  229.             if (Triggers[i].num_links != 0)
  230.                 err_printf(my_file, "Error: Exit triggers must have 0 links, this one has %i links.\n", Triggers[i].num_links);
  231.  
  232.             //  Find wall pointing to this trigger.
  233.             count2 = 0;
  234.             for (j=0; j<Num_walls; j++)
  235.                 if (Walls[j].trigger == i) {
  236.                     count2++;
  237.                     fprintf(my_file, "Exit trigger %i is in segment %i, on side %i, bound to wall %i\n", i, Walls[j].segnum, Walls[j].sidenum, j);
  238.                 }
  239.             if (count2 == 0)
  240.                 err_printf(my_file, "Error: Trigger %i is not bound to any wall.\n", i);
  241.             else if (count2 > 1)
  242.                 err_printf(my_file, "Error: Trigger %i is bound to %i walls.\n", i, count2);
  243.  
  244.         }
  245.  
  246.     if (count == 0)
  247.         err_printf(my_file, "Error: No exit trigger in this mine.\n");
  248.     else if (count != 1)
  249.         err_printf(my_file, "Error: More than one exit trigger in this mine.\n");
  250.     else
  251.         fprintf(my_file, "\n");
  252.  
  253.     //  ---------- Find exit doors ----------
  254.     count = 0;
  255.     for (i=0; i<=Highest_segment_index; i++)
  256.         for (j=0; j<MAX_SIDES_PER_SEGMENT; j++)
  257.             if (Segments[i].children[j] == -2) {
  258.                 fprintf(my_file, "Segment %3i, side %i is an exit door.\n", i, j);
  259.                 count++;
  260.             }
  261.  
  262.     if (count == 0)
  263.         err_printf(my_file, "Error: No external wall in this mine.\n");
  264.     else if (count != 1) {
  265.         warning_printf(my_file, "Warning: %i external walls in this mine.\n", count);
  266.         warning_printf(my_file, "(If %i are secret exits, then no problem.)\n", count-1); 
  267.     } else
  268.         fprintf(my_file, "\n");
  269. }
  270.  
  271. //  -----------------------------------------------------------------------------------------------------------
  272. void write_key_text(FILE *my_file)
  273. {
  274.     int i;
  275.     int red_count, blue_count, gold_count;
  276.     int red_count2, blue_count2, gold_count2;
  277.     int blue_segnum=-1, blue_sidenum=-1, red_segnum=-1, red_sidenum=-1, gold_segnum=-1, gold_sidenum=-1;
  278.     int connect_side;
  279.  
  280.     fprintf(my_file, "-----------------------------------------------------------------------------\n");
  281.     fprintf(my_file, "Key stuff:\n");
  282.  
  283.     red_count = 0;
  284.     blue_count = 0;
  285.     gold_count = 0;
  286.  
  287.     for (i=0; i<Num_walls; i++) {
  288.         if (Walls[i].keys & KEY_BLUE) {
  289.             fprintf(my_file, "Wall %i (seg=%i, side=%i) is keyed to the blue key.\n", i, Walls[i].segnum, Walls[i].sidenum);
  290.             if (blue_segnum == -1) {
  291.                 blue_segnum = Walls[i].segnum;
  292.                 blue_sidenum = Walls[i].sidenum;
  293.                 blue_count++;
  294.             } else {
  295.                 connect_side = find_connect_side(&Segments[Walls[i].segnum], &Segments[blue_segnum]);
  296.                 if (connect_side != blue_sidenum) {
  297.                     warning_printf(my_file, "Warning: This blue door at seg %i, is different than the one at seg %i, side %i\n", Walls[i].segnum, blue_segnum, blue_sidenum);
  298.                     blue_count++;
  299.                 }
  300.             }
  301.         }
  302.         if (Walls[i].keys & KEY_RED) {
  303.             fprintf(my_file, "Wall %i (seg=%i, side=%i) is keyed to the red key.\n", i, Walls[i].segnum, Walls[i].sidenum);
  304.             if (red_segnum == -1) {
  305.                 red_segnum = Walls[i].segnum;
  306.                 red_sidenum = Walls[i].sidenum;
  307.                 red_count++;
  308.             } else {
  309.                 connect_side = find_connect_side(&Segments[Walls[i].segnum], &Segments[red_segnum]);
  310.                 if (connect_side != red_sidenum) {
  311.                     warning_printf(my_file, "Warning: This red door at seg %i, is different than the one at seg %i, side %i\n", Walls[i].segnum, red_segnum, red_sidenum);
  312.                     red_count++;
  313.                 }
  314.             }
  315.         }
  316.         if (Walls[i].keys & KEY_GOLD) {
  317.             fprintf(my_file, "Wall %i (seg=%i, side=%i) is keyed to the gold key.\n", i, Walls[i].segnum, Walls[i].sidenum);
  318.             if (gold_segnum == -1) {
  319.                 gold_segnum = Walls[i].segnum;
  320.                 gold_sidenum = Walls[i].sidenum;
  321.                 gold_count++;
  322.             } else {
  323.                 connect_side = find_connect_side(&Segments[Walls[i].segnum], &Segments[gold_segnum]);
  324.                 if (connect_side != gold_sidenum) {
  325.                     warning_printf(my_file, "Warning: This gold door at seg %i, is different than the one at seg %i, side %i\n", Walls[i].segnum, gold_segnum, gold_sidenum);
  326.                     gold_count++;
  327.                 }
  328.             }
  329.         }
  330.     }
  331.  
  332.     if (blue_count > 1)
  333.         warning_printf(my_file, "Warning: %i doors are keyed to the blue key.\n", blue_count);
  334.  
  335.     if (red_count > 1)
  336.         warning_printf(my_file, "Warning: %i doors are keyed to the red key.\n", red_count);
  337.  
  338.     if (gold_count > 1)
  339.         warning_printf(my_file, "Warning: %i doors are keyed to the gold key.\n", gold_count);
  340.  
  341.     red_count2 = 0;
  342.     blue_count2 = 0;
  343.     gold_count2 = 0;
  344.  
  345.     for (i=0; i<=Highest_object_index; i++) {
  346.         if (Objects[i].type == OBJ_POWERUP)
  347.             if (Objects[i].id == POW_KEY_BLUE) {
  348.                 fprintf(my_file, "The BLUE key is object %i in segment %i\n", i, Objects[i].segnum);
  349.                 blue_count2++;
  350.             }
  351.         if (Objects[i].type == OBJ_POWERUP)
  352.             if (Objects[i].id == POW_KEY_RED) {
  353.                 fprintf(my_file, "The RED key is object %i in segment %i\n", i, Objects[i].segnum);
  354.                 red_count2++;
  355.             }
  356.         if (Objects[i].type == OBJ_POWERUP)
  357.             if (Objects[i].id == POW_KEY_GOLD) {
  358.                 fprintf(my_file, "The GOLD key is object %i in segment %i\n", i, Objects[i].segnum);
  359.                 gold_count2++;
  360.             }
  361.  
  362.         if (Objects[i].contains_count) {
  363.             if (Objects[i].contains_type == OBJ_POWERUP) {
  364.                 switch (Objects[i].contains_id) {
  365.                     case POW_KEY_BLUE:
  366.                         fprintf(my_file, "The BLUE key is contained in object %i (a %s %s) in segment %i\n", i, Object_type_names[Objects[i].type], Robot_names[Objects[i].id], Objects[i].segnum);
  367.                         blue_count2 += Objects[i].contains_count;
  368.                         break;
  369.                     case POW_KEY_GOLD:
  370.                         fprintf(my_file, "The GOLD key is contained in object %i (a %s %s) in segment %i\n", i, Object_type_names[Objects[i].type], Robot_names[Objects[i].id], Objects[i].segnum);
  371.                         gold_count2 += Objects[i].contains_count;
  372.                         break;
  373.                     case POW_KEY_RED:
  374.                         fprintf(my_file, "The RED key is contained in object %i (a %s %s) in segment %i\n", i, Object_type_names[Objects[i].type], Robot_names[Objects[i].id], Objects[i].segnum);
  375.                         red_count2 += Objects[i].contains_count;
  376.                         break;
  377.                     default:
  378.                         break;
  379.                 }
  380.             }
  381.         }
  382.     }
  383.  
  384.     if (blue_count)
  385.         if (blue_count2 == 0)
  386.             err_printf(my_file, "Error: There is a door keyed to the blue key, but no blue key!\n");
  387.  
  388.     if (red_count)
  389.         if (red_count2 == 0)
  390.             err_printf(my_file, "Error: There is a door keyed to the red key, but no red key!\n");
  391.  
  392.     if (gold_count)
  393.         if (gold_count2 == 0)
  394.             err_printf(my_file, "Error: There is a door keyed to the gold key, but no gold key!\n");
  395.  
  396.     if (blue_count2 > 1)
  397.         err_printf(my_file, "Error: There are %i blue keys!\n", blue_count2);
  398.  
  399.     if (red_count2 > 1)
  400.         err_printf(my_file, "Error: There are %i red keys!\n", red_count2);
  401.  
  402.     if (gold_count2 > 1)
  403.         err_printf(my_file, "Error: There are %i gold keys!\n", gold_count2);
  404. }
  405.  
  406. //  ------------------------------------------------------------------------------------------
  407. void write_control_center_text(FILE *my_file)
  408. {
  409.     int i, count, objnum, count2;
  410.  
  411.     fprintf(my_file, "-----------------------------------------------------------------------------\n");
  412.     fprintf(my_file, "Control Center stuff:\n");
  413.  
  414.     count = 0;
  415.     for (i=0; i<=Highest_segment_index; i++)
  416.         if (Segments[i].special == SEGMENT_IS_CONTROLCEN) {
  417.             count++;
  418.             fprintf(my_file, "Segment %3i is a control center.\n", i);
  419.             objnum = Segments[i].objects;
  420.             count2 = 0;
  421.             while (objnum != -1) {
  422.                 if (Objects[objnum].type == OBJ_CNTRLCEN)
  423.                     count2++;
  424.                 objnum = Objects[objnum].next;
  425.             }
  426.             if (count2 == 0)
  427.                 fprintf(my_file, "No control center object in control center segment.\n");
  428.             else if (count2 != 1)
  429.                 fprintf(my_file, "%i control center objects in control center segment.\n", count2);
  430.         }
  431.  
  432.     if (count == 0)
  433.         err_printf(my_file, "Error: No control center in this mine.\n");
  434.     else if (count != 1)
  435.         err_printf(my_file, "Error: More than one control center in this mine.\n");
  436. }
  437.  
  438. //  ------------------------------------------------------------------------------------------
  439. void write_fuelcen_text(FILE *my_file)
  440. {
  441.     int i;
  442.  
  443.     fprintf(my_file, "-----------------------------------------------------------------------------\n");
  444.     fprintf(my_file, "Fuel Center stuff: (Note: This means fuel, repair, materialize, control centers!)\n");
  445.  
  446.     for (i=0; i<Num_fuelcenters; i++) {
  447.         fprintf(my_file, "Fuelcenter %i: Type=%i (%s), segment = %3i\n", i, Station[i].Type, Special_names[Station[i].Type], Station[i].segnum);
  448.         if (Segments[Station[i].segnum].special != Station[i].Type)
  449.             err_printf(my_file, "Error: Conflicting data: Segment %i has special type %i (%s), expected to be %i\n", Station[i].segnum, Segments[Station[i].segnum].special, Special_names[Segments[Station[i].segnum].special], Station[i].Type);
  450.     }
  451. }
  452.  
  453. //  ------------------------------------------------------------------------------------------
  454. void write_segment_text(FILE *my_file)
  455. {
  456.     int i, objnum;
  457.  
  458.     fprintf(my_file, "-----------------------------------------------------------------------------\n");
  459.     fprintf(my_file, "Segment stuff:\n");
  460.  
  461.     for (i=0; i<=Highest_segment_index; i++) {
  462.  
  463.         fprintf(my_file, "Segment %4i: ", i);
  464.         if (Segments[i].special != 0)
  465.             fprintf(my_file, "special = %3i (%s), value = %3i ", Segments[i].special, Special_names[Segments[i].special], Segments[i].value);
  466.  
  467.         if (Segments[i].matcen_num != -1)
  468.             fprintf(my_file, "matcen = %3i, ", Segments[i].matcen_num);
  469.         
  470.         fprintf(my_file, "\n");
  471.     }
  472.  
  473.     for (i=0; i<=Highest_segment_index; i++) {
  474.         int depth;
  475.  
  476.         objnum = Segments[i].objects;
  477.         fprintf(my_file, "Segment %4i: ", i);
  478.         depth=0;
  479.         if (objnum != -1) {
  480.             fprintf(my_file, "Objects: ");
  481.             while (objnum != -1) {
  482.                 fprintf(my_file, "[%8s %8s %3i] ", object_types(objnum), object_ids(objnum), objnum);
  483.                 objnum = Objects[objnum].next;
  484.                 if (depth++ > 30) {
  485.                     fprintf(my_file, "\nAborted after %i links\n", depth);
  486.                     break;
  487.                 }
  488.             }
  489.         }
  490.         fprintf(my_file, "\n");
  491.     }
  492. }
  493.  
  494. //  ------------------------------------------------------------------------------------------
  495. //  This routine is bogus.  It assumes that all centers are matcens, which is not true.  The setting of segnum is bogus.
  496. void write_matcen_text(FILE *my_file)
  497. {
  498.     int i, j, k;
  499.  
  500.     fprintf(my_file, "-----------------------------------------------------------------------------\n");
  501.     fprintf(my_file, "Materialization centers:\n");
  502.     for (i=0; i<Num_robot_centers; i++) {
  503.         int trigger_count=0, segnum, fuelcen_num;
  504.  
  505.         fprintf(my_file, "FuelCenter[%02i].Segment = %04i  ", i, Station[i].segnum);
  506.         fprintf(my_file, "Segment[%04i].matcen_num = %02i  ", Station[i].segnum, Segments[Station[i].segnum].matcen_num);
  507.  
  508.         fuelcen_num = RobotCenters[i].fuelcen_num;
  509.         if (Station[fuelcen_num].Type != SEGMENT_IS_ROBOTMAKER)
  510.             err_printf(my_file, "Error: Matcen %i corresponds to Station %i, which has type %i (%s).\n", i, fuelcen_num, Station[fuelcen_num].Type, Special_names[Station[fuelcen_num].Type]);
  511.  
  512.         segnum = Station[fuelcen_num].segnum;
  513.  
  514.         //  Find trigger for this materialization center.
  515.         for (j=0; j<Num_triggers; j++) {
  516.             if (Triggers[j].flags & TRIGGER_MATCEN) {
  517.                 for (k=0; k<Triggers[j].num_links; k++)
  518.                     if (Triggers[j].seg[k] == segnum) {
  519.                         fprintf(my_file, "Trigger = %2i  ", j );
  520.                         trigger_count++;
  521.                     }
  522.             }
  523.         }
  524.         fprintf(my_file, "\n");
  525.  
  526.         if (trigger_count == 0)
  527.             err_printf(my_file, "Error: Matcen %i in segment %i has no trigger!\n", i, segnum);
  528.  
  529.     }
  530. }
  531.  
  532. //  ------------------------------------------------------------------------------------------
  533. void write_wall_text(FILE *my_file)
  534. {
  535.     int i, j;
  536.     byte    wall_flags[MAX_WALLS];
  537.  
  538.     fprintf(my_file, "-----------------------------------------------------------------------------\n");
  539.     fprintf(my_file, "Walls:\n");
  540.     for (i=0; i<Num_walls; i++) {
  541.         int segnum, sidenum;
  542.  
  543.         fprintf(my_file, "Wall %03i: seg=%3i, side=%2i, linked_wall=%3i, type=%s, flags=%4x, hps=%3i, trigger=%2i, clip_num=%2i, keys=%2i, state=%i\n", i,
  544.             Walls[i].segnum, Walls[i].sidenum, Walls[i].linked_wall, Wall_names[Walls[i].type], Walls[i].flags, Walls[i].hps >> 16, Walls[i].trigger, Walls[i].clip_num, Walls[i].keys, Walls[i].state);
  545.  
  546.         segnum = Walls[i].segnum;
  547.         sidenum = Walls[i].sidenum;
  548.  
  549.         if (Segments[segnum].sides[sidenum].wall_num != i)
  550.             err_printf(my_file, "Error: Wall %i points at segment %i, side %i, but that segment doesn't point back (it's wall_num = %i)\n", i, segnum, sidenum, Segments[segnum].sides[sidenum].wall_num);
  551.     }
  552.  
  553.     for (i=0; i<MAX_WALLS; i++)
  554.         wall_flags[i] = 0;
  555.  
  556.     for (i=0; i<=Highest_segment_index; i++) {
  557.         segment *segp = &Segments[i];
  558.         for (j=0; j<MAX_SIDES_PER_SEGMENT; j++) {
  559.             side    *sidep = &segp->sides[j];
  560.             if (sidep->wall_num != -1)
  561.                 if (wall_flags[sidep->wall_num])
  562.                     err_printf(my_file, "Error: Wall %i appears in two or more segments, including segment %i, side %i.\n", sidep->wall_num, i, j);
  563.                 else
  564.                     wall_flags[sidep->wall_num] = 1;
  565.         }
  566.     }
  567.  
  568. }
  569.  
  570. //typedef struct trigger {
  571. //  byte        type;
  572. //  short       flags;
  573. //  fix     value;
  574. //  fix     time;
  575. //  byte        link_num;
  576. //  short   num_links;
  577. //  short   seg[MAX_WALLS_PER_LINK];
  578. //  short       side[MAX_WALLS_PER_LINK];
  579. //  } trigger;
  580.  
  581. //  ------------------------------------------------------------------------------------------
  582. void write_player_text(FILE *my_file)
  583. {
  584.     int i, num_players=0;
  585.  
  586.     fprintf(my_file, "-----------------------------------------------------------------------------\n");
  587.     fprintf(my_file, "Players:\n");
  588.     for (i=0; i<=Highest_object_index; i++) {
  589.         if (Objects[i].type == OBJ_PLAYER) {
  590.             num_players++;
  591.             fprintf(my_file, "Player %2i is object #%3i in segment #%3i.\n", Objects[i].id, i, Objects[i].segnum);
  592.         }
  593.     }
  594.  
  595. #ifdef SHAREWARE    
  596.     if (num_players != MAX_PLAYERS)
  597.         err_printf(my_file, "Error: %i player objects.  %i are required.\n", num_players, MAX_PLAYERS);
  598. #endif
  599. #ifndef SHAREWARE   
  600.     if (num_players > MAX_MULTI_PLAYERS)
  601.         err_printf(my_file, "Error: %i player objects.  %i are required.\n", num_players, MAX_PLAYERS);
  602. #endif
  603.  
  604.  
  605. }
  606.  
  607. //  ------------------------------------------------------------------------------------------
  608. void write_trigger_text(FILE *my_file)
  609. {
  610.     int i, j, w;
  611.  
  612.     fprintf(my_file, "-----------------------------------------------------------------------------\n");
  613.     fprintf(my_file, "Triggers:\n");
  614.     for (i=0; i<Num_triggers; i++) {
  615.         fprintf(my_file, "Trigger %03i: type=%3i flags=%04x, value=%08x, time=%8x, linknum=%i, num_links=%i ", i, 
  616.             Triggers[i].type, Triggers[i].flags, Triggers[i].value, Triggers[i].time, Triggers[i].link_num, Triggers[i].num_links);
  617.  
  618.         for (j=0; j<Triggers[i].num_links; j++)
  619.             fprintf(my_file, "[%03i:%i] ", Triggers[i].seg[j], Triggers[i].side[j]);
  620.  
  621.         //  Find which wall this trigger is connected to.
  622.         for (w=0; w<Num_walls; w++)
  623.             if (Walls[w].trigger == i)
  624.                 break;
  625.  
  626.         if (w == Num_walls)
  627.             err_printf(my_file, "\nError: Trigger %i is not connected to any wall, so it can never be triggered.\n", i);
  628.         else
  629.             fprintf(my_file, "Attached to seg:side = %i:%i, wall %i\n", Walls[w].segnum, Walls[w].sidenum, Segments[Walls[w].segnum].sides[Walls[w].sidenum].wall_num);
  630.  
  631.     }
  632.  
  633. }
  634.  
  635. //  ------------------------------------------------------------------------------------------
  636. void write_game_text_file(char *filename)
  637. {
  638.     char    my_filename[128];
  639.     int namelen;
  640.     FILE    * my_file;
  641.  
  642.     Errors_in_mine = 0;
  643.  
  644.     // mprintf((0, "Writing text file for mine [%s]\n", filename));
  645.  
  646.     namelen = strlen(filename);
  647.  
  648.     Assert (namelen > 4);
  649.  
  650.     Assert (filename[namelen-4] == '.');
  651.  
  652.     strcpy(my_filename, filename);
  653.     strcpy( &my_filename[namelen-4], ".txm");
  654.  
  655.     // mprintf((0, "Writing text file [%s]\n", my_filename));
  656.  
  657.     my_file = fopen( my_filename, "wt" );
  658.  
  659.     if (!my_file)   {
  660.         char  ErrorMessage[200];
  661.  
  662.         sprintf( ErrorMessage, "ERROR: Unable to open output file %s\n", my_file );
  663.         stop_time();
  664.         gr_palette_load(gr_palette);
  665.         nm_messagebox( NULL, 1, "Ok", ErrorMessage );
  666.         start_time();
  667.  
  668.         return;
  669.     }
  670.  
  671.     dump_used_textures_level(my_file, 0);
  672.     say_totals(my_file, Gamesave_current_filename);
  673.  
  674.     fprintf(my_file, "\nNumber of segments:   %4i\n", Highest_segment_index+1);
  675.     fprintf(my_file, "Number of objects:    %4i\n", Highest_object_index+1);
  676.     fprintf(my_file, "Number of walls:      %4i\n", Num_walls);
  677.     fprintf(my_file, "Number of open doors: %4i\n", Num_open_doors);
  678.     fprintf(my_file, "Number of triggers:   %4i\n", Num_triggers);
  679.     fprintf(my_file, "Number of matcens:    %4i\n", Num_robot_centers);
  680.     fprintf(my_file, "\n");
  681.  
  682.     write_segment_text(my_file);
  683.  
  684.     write_fuelcen_text(my_file);
  685.  
  686.     write_matcen_text(my_file);
  687.  
  688.     write_player_text(my_file);
  689.  
  690.     write_wall_text(my_file);
  691.  
  692.     write_trigger_text(my_file);
  693.  
  694.     write_exit_text(my_file);
  695.  
  696.     //  ---------- Find control center segment ----------
  697.     write_control_center_text(my_file);
  698.  
  699.     //  ---------- Show keyed walls ----------
  700.     write_key_text(my_file);
  701.  
  702.     fclose(my_file);
  703.  
  704. }
  705.  
  706. // -- //    ---------------
  707. // -- //    Note: This only works for a loaded level because the objects array must be valid.
  708. // -- void determine_used_textures_robots(int *tmap_buf)
  709. // -- {
  710. // --   int i, objnum;
  711. // --   polymodel   *po;
  712. // -- 
  713. // --   Assert(N_polygon_models);
  714. // -- 
  715. // --   for (objnum=0; objnum <= Highest_object_index; objnum++) {
  716. // --       int model_num;
  717. // -- 
  718. // --       if (Objects[objnum].render_type == RT_POLYOBJ) {
  719. // --           model_num = Objects[objnum].rtype.pobj_info.model_num;
  720. // -- 
  721. // --           po=&Polygon_models[model_num];
  722. // -- 
  723. // --           for (i=0;i<po->n_textures;i++)  {
  724. // --               int tli;
  725. // -- 
  726. // --               tli = ObjBitmaps[ObjBitmapPtrs[po->first_texture+i]];
  727. // --               Assert((tli>=0) && (tli<= Num_tmaps));
  728. // --               tmap_buf[tli]++;
  729. // --           }
  730. // --       }
  731. // --   }
  732. // -- 
  733. // -- }
  734.  
  735. //  -----------------------------------------------------------------------------
  736. void determine_used_textures_level(int load_level_flag, int shareware_flag, int level_num, int *tmap_buf, int *wall_buf, byte *level_tmap_buf, int max_tmap)
  737. {
  738.     int segnum, sidenum;
  739.     int i, j;
  740.  
  741.     for (i=0; i<max_tmap; i++)
  742.         tmap_buf[i] = 0;
  743.  
  744.     if (load_level_flag) {
  745.         if (shareware_flag)
  746.             load_level(Shareware_level_names[level_num]);
  747.         else
  748.             load_level(Registered_level_names[level_num]);
  749.     }
  750.  
  751.     for (segnum=0; segnum<=Highest_segment_index; segnum++) {
  752.         segment *segp = &Segments[segnum];
  753.  
  754.         for (sidenum=0; sidenum<MAX_SIDES_PER_SEGMENT; sidenum++) {
  755.             side    *sidep = &segp->sides[sidenum];
  756.  
  757.             if (sidep->wall_num != -1) {
  758.                 int clip_num = Walls[sidep->wall_num].clip_num;
  759.                 if (clip_num != -1) {
  760.  
  761.                     int num_frames = WallAnims[clip_num].num_frames;
  762.  
  763.                     wall_buf[clip_num] = 1;
  764.  
  765.                     for (j=0; j<num_frames; j++) {
  766.                         int tmap_num;
  767.  
  768.                         tmap_num = WallAnims[clip_num].frames[j];
  769.                         tmap_buf[tmap_num]++;
  770.                         if (level_tmap_buf[tmap_num] == -1)
  771.                             level_tmap_buf[tmap_num] = level_num + (!shareware_flag) * NUM_SHAREWARE_LEVELS;
  772.                     }
  773.                 }
  774.             }
  775.  
  776.             if (sidep->tmap_num >= 0)
  777.                 if (sidep->tmap_num < max_tmap) {
  778.                     tmap_buf[sidep->tmap_num]++;
  779.                     if (level_tmap_buf[sidep->tmap_num] == -1)
  780.                         level_tmap_buf[sidep->tmap_num] = level_num + (!shareware_flag) * NUM_SHAREWARE_LEVELS;
  781.                 } else
  782.                     Int3(); //  Error, bogus texture map.  Should not be greater than max_tmap.
  783.  
  784.             if ((sidep->tmap_num2 & 0x3fff) != 0)
  785.                 if ((sidep->tmap_num2 & 0x3fff) < max_tmap) {
  786.                     tmap_buf[sidep->tmap_num2 & 0x3fff]++;
  787.                     if (level_tmap_buf[sidep->tmap_num2 & 0x3fff] == -1)
  788.                         level_tmap_buf[sidep->tmap_num2 & 0x3fff] = level_num + (!shareware_flag) * NUM_SHAREWARE_LEVELS;
  789.                 } else
  790.                     Int3(); //  Error, bogus texture map.  Should not be greater than max_tmap.
  791.         }
  792.     }
  793. }
  794.  
  795. //  -----------------------------------------------------------------------------
  796. void merge_buffers(int *dest, int *src, int num)
  797. {
  798.     int i;
  799.  
  800.     for (i=0; i<num; i++)
  801.         if (src[i])
  802.             dest[i] += src[i];
  803. }
  804.  
  805. //  -----------------------------------------------------------------------------
  806. void say_used_tmaps(FILE *my_file, int *tb)
  807. {
  808.     int i;
  809.     int count = 0;
  810.  
  811.     for (i=0; i<Num_tmaps; i++)
  812.         if (tb[i]) {
  813.             fprintf(my_file, "[%3i %8s (%4i)] ", i, TmapInfo[i].filename, tb[i]);
  814.             if (count++ >= 4) {
  815.                 fprintf(my_file, "\n");
  816.                 count = 0;
  817.             }
  818.         }
  819. }
  820.  
  821. //  -----------------------------------------------------------------------------
  822. void say_used_once_tmaps(FILE *my_file, int *tb, byte *tb_lnum)
  823. {
  824.     int i;
  825.     char    *level_name;
  826.  
  827.     for (i=0; i<Num_tmaps; i++)
  828.         if (tb[i] == 1) {
  829.             int level_num = tb_lnum[i];
  830.             if (level_num >= NUM_SHAREWARE_LEVELS) {
  831.                 Assert((level_num - NUM_SHAREWARE_LEVELS >= 0) && (level_num - NUM_SHAREWARE_LEVELS < NUM_REGISTERED_LEVELS));
  832.                 level_name = Registered_level_names[level_num - NUM_SHAREWARE_LEVELS];
  833.             } else {
  834.                 Assert((level_num >= 0) && (level_num < NUM_SHAREWARE_LEVELS));
  835.                 level_name = Shareware_level_names[level_num];
  836.             }
  837.  
  838.             fprintf(my_file, "Texture %3i %8s used only once on level %s\n", i, TmapInfo[i].filename, level_name);
  839.         }
  840. }
  841.  
  842. //  -----------------------------------------------------------------------------
  843. void say_unused_tmaps(FILE *my_file, int *tb)
  844. {
  845.     int i;
  846.     int count = 0;
  847.  
  848.     for (i=0; i<Num_tmaps; i++)
  849.         if (!tb[i]) {
  850.             if (GameBitmaps[Textures[i].index].bm_data == &bogus_data)
  851.                 fprintf(my_file, "U");
  852.             else
  853.                 fprintf(my_file, " ");
  854.  
  855.             fprintf(my_file, "[%3i %8s] ", i, TmapInfo[i].filename);
  856.             if (count++ >= 4) {
  857.                 fprintf(my_file, "\n");
  858.                 count = 0;
  859.             }
  860.         }
  861. }
  862.  
  863. //  -----------------------------------------------------------------------------
  864. void say_unused_walls(FILE *my_file, int *tb)
  865. {
  866.     int i;
  867.  
  868.     for (i=0; i<Num_wall_anims; i++)
  869.         if (!tb[i])
  870.             fprintf(my_file, "Wall %3i is unused.\n", i);
  871. }
  872.  
  873. //  -------------------------------------------------------------------------------------------------
  874. say_totals(FILE *my_file, char *level_name)
  875. {
  876.     int i, objnum;
  877.     int total_robots = 0;
  878.     int objects_processed = 0;
  879.  
  880.     int used_objects[MAX_OBJECTS];
  881.  
  882.     fprintf(my_file, "\nLevel %s\n", level_name);
  883.  
  884.     for (i=0; i<MAX_OBJECTS; i++)
  885.         used_objects[i] = 0;
  886.  
  887.     while (objects_processed < Highest_object_index+1) {
  888.         int j, objtype, objid, objcount, cur_obj_val, min_obj_val, min_objnum;
  889.  
  890.         //  Find new min objnum.
  891.         min_obj_val = 0x7fff0000;
  892.         min_objnum = -1;
  893.  
  894.         for (j=0; j<=Highest_object_index; j++) {
  895.             if (!used_objects[j]) {
  896.                 cur_obj_val = Objects[j].type * 1000 + Objects[j].id;
  897.                 if (cur_obj_val < min_obj_val) {
  898.                     min_objnum = j;
  899.                     min_obj_val = cur_obj_val;
  900.                 }
  901.             }
  902.         }
  903.         if (min_objnum == -1)
  904.             break;
  905.  
  906.         objcount = 0;
  907.  
  908.         objtype = Objects[min_objnum].type;
  909.         objid = Objects[min_objnum].id;
  910.  
  911.         for (i=0; i<=Highest_object_index; i++) {
  912.             if (!used_objects[i]) {
  913.  
  914.                 if (((Objects[i].type == objtype) && (Objects[i].id == objid)) ||
  915.                         ((Objects[i].type == objtype) && (objtype == OBJ_PLAYER)) ||
  916.                         ((Objects[i].type == objtype) && (objtype == OBJ_COOP)) ||
  917.                         ((Objects[i].type == objtype) && (objtype == OBJ_HOSTAGE))) {
  918.                     if (Objects[i].type == OBJ_ROBOT)
  919.                         total_robots++;
  920.                     used_objects[i] = 1;
  921.                     objcount++;
  922.                     objects_processed++;
  923.                 }
  924.             }
  925.         }
  926.  
  927.         if (objcount) {
  928.             fprintf(my_file, "Object: ");
  929.             fprintf(my_file, "%8s %8s %3i\n", object_types(min_objnum), object_ids(min_objnum), objcount);
  930.         }
  931.     }
  932.  
  933.     fprintf(my_file, "Total robots = %3i\n", total_robots);
  934. }
  935.  
  936. //  -----------------------------------------------------------------------------
  937. void say_totals_all(void)
  938. {
  939.     int i;
  940.     FILE    *my_file;
  941.  
  942.     my_file = fopen( "levels.all", "wt" );
  943.  
  944.     if (!my_file)   {
  945.         char  ErrorMessage[200];
  946.  
  947.         sprintf( ErrorMessage, "ERROR: Unable to open output file levels.all\n");
  948.         stop_time();
  949.         gr_palette_load(gr_palette);
  950.         nm_messagebox( NULL, 1, "Ok", ErrorMessage );
  951.         start_time();
  952.  
  953.         return;
  954.     }
  955.  
  956.     for (i=0; i<NUM_SHAREWARE_LEVELS; i++) {
  957.         mprintf((0, "Level %i\n", i+1));
  958.         load_level(Shareware_level_names[i]);
  959.         say_totals(my_file, Shareware_level_names[i]);
  960.     }
  961.  
  962.     for (i=0; i<NUM_REGISTERED_LEVELS; i++) {
  963.         mprintf((0, "Level %i\n", i+1+NUM_SHAREWARE_LEVELS));
  964.         load_level(Registered_level_names[i]);
  965.         say_totals(my_file, Registered_level_names[i]);
  966.     }
  967.  
  968.     fclose(my_file);
  969.  
  970. }
  971.  
  972. void dump_used_textures_level(FILE *my_file, int level_num)
  973. {
  974.     int i;
  975.     int temp_tmap_buf[MAX_TEXTURES];
  976.     int perm_tmap_buf[MAX_TEXTURES];
  977.     byte    level_tmap_buf[MAX_TEXTURES];
  978.     int temp_wall_buf[MAX_WALL_ANIMS];
  979.     int perm_wall_buf[MAX_WALL_ANIMS];
  980.  
  981.     for (i=0; i<MAX_TEXTURES; i++) {
  982.         perm_tmap_buf[i] = 0;
  983.         level_tmap_buf[i] = -1;
  984.     }
  985.  
  986.     for (i=0; i<MAX_WALL_ANIMS; i++) {
  987.         perm_wall_buf[i] = 0;
  988.     }
  989.  
  990.     determine_used_textures_level(0, 1, level_num, temp_tmap_buf, temp_wall_buf, level_tmap_buf, MAX_TEXTURES);
  991. // --   determine_used_textures_robots(temp_tmap_buf);
  992.     fprintf(my_file, "\nTextures used in [%s]\n", Gamesave_current_filename);
  993.     say_used_tmaps(my_file, temp_tmap_buf);
  994. }
  995.  
  996. //  -----------------------------------------------------------------------------
  997. void dump_used_textures_all(void)
  998. {
  999.     FILE    *my_file;
  1000.     int i;
  1001.     int temp_tmap_buf[MAX_TEXTURES];
  1002.     int perm_tmap_buf[MAX_TEXTURES];
  1003.     byte    level_tmap_buf[MAX_TEXTURES];
  1004.     int temp_wall_buf[MAX_WALL_ANIMS];
  1005.     int perm_wall_buf[MAX_WALL_ANIMS];
  1006.  
  1007. say_totals_all();
  1008.  
  1009.     my_file = fopen( "textures.dmp", "wt" );
  1010.  
  1011.     if (!my_file)   {
  1012.         char  ErrorMessage[200];
  1013.  
  1014.         sprintf( ErrorMessage, "ERROR: Unable to open output file textures.dmp\n");
  1015.         stop_time();
  1016.         gr_palette_load(gr_palette);
  1017.         nm_messagebox( NULL, 1, "Ok", ErrorMessage );
  1018.         start_time();
  1019.  
  1020.         return;
  1021.     }
  1022.  
  1023.     for (i=0; i<MAX_TEXTURES; i++) {
  1024.         perm_tmap_buf[i] = 0;
  1025.         level_tmap_buf[i] = -1;
  1026.     }
  1027.  
  1028.     for (i=0; i<MAX_WALL_ANIMS; i++) {
  1029.         perm_wall_buf[i] = 0;
  1030.     }
  1031.  
  1032.     for (i=0; i<NUM_SHAREWARE_LEVELS; i++) {
  1033.         determine_used_textures_level(1, 1, i, temp_tmap_buf, temp_wall_buf, level_tmap_buf, MAX_TEXTURES);
  1034.         fprintf(my_file, "\nTextures used in [%s]\n", Shareware_level_names[i]);
  1035.         say_used_tmaps(my_file, temp_tmap_buf);
  1036.         merge_buffers(perm_tmap_buf, temp_tmap_buf, MAX_TEXTURES);
  1037.         merge_buffers(perm_wall_buf, temp_wall_buf, MAX_WALL_ANIMS);
  1038.     }
  1039.  
  1040.     fprintf(my_file, "\n\nUsed textures in all shareware mines:\n");
  1041.     say_used_tmaps(my_file, perm_tmap_buf);
  1042.  
  1043.     fprintf(my_file, "\nUnused textures in all shareware mines:\n");
  1044.     say_unused_tmaps(my_file, perm_tmap_buf);
  1045.  
  1046.     fprintf(my_file, "\nTextures used exactly once in all shareware mines:\n");
  1047.     say_used_once_tmaps(my_file, perm_tmap_buf, level_tmap_buf);
  1048.  
  1049.     fprintf(my_file, "\nWall anims (eg, doors) unused in all shareware mines:\n");
  1050.     say_unused_walls(my_file, perm_wall_buf);
  1051.  
  1052.     for (i=0; i<NUM_REGISTERED_LEVELS; i++) {
  1053.         determine_used_textures_level(1, 0, i, temp_tmap_buf, temp_wall_buf, level_tmap_buf, MAX_TEXTURES);
  1054.         fprintf(my_file, "\nTextures used in [%s]\n", Registered_level_names[i]);
  1055.         say_used_tmaps(my_file, temp_tmap_buf);
  1056.         merge_buffers(perm_tmap_buf, temp_tmap_buf, MAX_TEXTURES);
  1057.     }
  1058.  
  1059.     fprintf(my_file, "\n\nUsed textures in all (including registered) mines:\n");
  1060.     say_used_tmaps(my_file, perm_tmap_buf);
  1061.  
  1062.     fprintf(my_file, "\nUnused textures in all (including registered) mines:\n");
  1063.     say_unused_tmaps(my_file, perm_tmap_buf);
  1064.  
  1065.     fclose(my_file);
  1066. }
  1067.  
  1068. #endif
  1069.